/*Copyright (C) 2009 Careil Baptiste

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Error.h"
#include "Network.h"
#include <errno.h>
#include <string.h>

CSLP_UDPSOCKET DLL_IMPEXP CSLP_InitUDPSocket()
{
	#ifdef WIN32
	InitWSA();
	#endif
	return socket(AF_INET, SOCK_DGRAM, 0);
}


int DLL_IMPEXP CSLP_Bind(CSLP_UDPSOCKET serverSock, unsigned short port)
{
	SOCKADDR_IN sockIn;
	sockIn.sin_addr.s_addr = htonl(INADDR_ANY);
	sockIn.sin_family = AF_INET;
	sockIn.sin_port = htons(port);
	memset(sockIn.sin_zero, 0, 8);
	return bind(serverSock, (SOCKADDR*)(&sockIn), sizeof(sockIn));
}

CSLP_NETWORK_ERROR DLL_IMPEXP CSLP_SendTo(CSLP_UDPSOCKET sock, const void* data, size_t dataLen, unsigned long IP, unsigned short port)
{
	CSLP_NETWORK_ERROR retVal = NONE;
	SOCKADDR_IN sockIn;
	sockIn.sin_addr.s_addr = IP;
	sockIn.sin_port = htons(port);
	sockIn.sin_family = AF_INET;
	memset(sockIn.sin_zero, 0, 8);
	
	if (sendto(sock, data, dataLen, MSG_NOSIGNAL, (SOCKADDR*)(&sockIn), sizeof(sockIn)) == -1)
	{
		retVal = CSLP_GetLastNetworkError();
	}
	return retVal;
}

CSLP_NETWORK_ERROR DLL_IMPEXP CSLP_ReceiveFrom(CSLP_UDPSOCKET sock, void* data, size_t dataLen, size_t* bytesWrite, unsigned long* IP, unsigned short* port)
{
	CSLP_NETWORK_ERROR retVal = NONE;
	int bytesReceive;
	SOCKADDR_IN sockIn;
	socklen_t sockInLen = sizeof(sockIn);

	if (data == NULL || bytesWrite == NULL || IP == NULL || port == NULL)
	{
		return ERROR;
	}

	bytesReceive = recvfrom(sock, data, dataLen, 0, (SOCKADDR*)(&sockIn), &sockInLen);
	if(bytesReceive == -1)
	{
		retVal = CSLP_GetLastNetworkError();
	}
	else
	{
		*bytesWrite = bytesReceive;
		*IP = sockIn.sin_addr.s_addr;
		*port = htons(sockIn.sin_port);
	}
	return retVal;
}

void DLL_IMPEXP CSLP_CloseUDPSocket(CSLP_UDPSOCKET sock)
{
	#ifdef WIN32
	if (closesocket((SOCKET)(sock)) == 0)
	{
		CloseWSA();
	}
	#else
	close((int)(sock));
	#endif
}
